from miniopy_async import Minio, S3Error
import aiofiles
import aiohttp
from typing import Optional

from common.log import log
from common.event import get_event_loop
from settings.config import settings

class MinioUtil():

    def __init__(
        self,
        url: str = None,
        access_key: str = None,
        secret_key: str = None,
        secure: bool = False
    ):
        self._url = url if url else settings.MINIO_URL
        self._access_key = access_key if access_key else settings.MINIO_ACCESSKEY
        self._secret_key = secret_key if secret_key else settings.MINIO_SECRETKEY
        self._secure = secure
        self._client = Minio(
            endpoint=self._url,
            access_key=self._access_key,
            secret_key=self._secret_key,
            secure=self._secure
        )
        
    async def upload_async(
        self, 
        file_path: str, 
        object_name: str, 
        bucket_name: str
    ) -> Optional[str]:
        """上传文件到 Minio

        Args:
            file_path (str): 文件路径
            object_name (str): 上传对象名
            bucket_name (str): 存储位置

        Returns:
            Optional[str]: 上传成功返回文件 url，否则 None
        """
        try:
            await self._client.fput_object(
                bucket_name=bucket_name,
                object_name=object_name,
                file_path=file_path
            )
            log.info(f"{file_path} 成功上传到 {bucket_name}/{object_name}")
            protocal = 'http' if not self._secure else 'https'
            return f"{protocal}://{self._url}/{bucket_name}/{object_name}"
        except Exception as e:
            log.error(f"minio 上传文件 {object_name} 失败: {e}")
        return None
    
    async def download_async(
        self, 
        save_path: str, 
        object_name: str, 
        bucket_name: str
    ) -> bool:
        """从 Minio 下载文件到指定位置

        Args:
            save_path (str): 文件保存位置
            object_name (str): 对象名
            bucket_name (str): 存储位置

        Returns:
            bool: True 表示下载成功；False 表示下载失败
        """
        try:
            async with aiohttp.ClientSession() as session:
                response = await self._client.get_object(
                    bucket_name=bucket_name,
                    object_name=object_name,
                    session=session
                )
                async with aiofiles.open(save_path, 'wb') as f:
                    async for chunk in response.content.iter_chunked(1024 * 1024):
                        await f.write(chunk)
            return True
        except S3Error as e:
            log.error(f"MinIO S3 错误: {e}")
        except Exception as e:
            log.error(f"minio 下载文件 {object_name} 失败: {e}")
        return False
    
    def upload_sync(
        self, 
        file_path: str, 
        object_name: str, 
        bucket_name: str
    ) -> Optional[str]:
        loop = get_event_loop()
        return loop.run_until_complete(
            self.upload_async(
                file_path=file_path,
                object_name=object_name,
                bucket_name=bucket_name
            )
        )
        
    def download_sync(
        self, 
        save_path: str, 
        object_name: str, 
        bucket_name: str
    ) -> bool:
        loop = get_event_loop()
        return loop.run_until_complete(
            self.download_async(
                save_path=save_path,
                object_name=object_name,
                bucket_name=bucket_name
            )
        )